package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

func f(msg string) {
	for i := 0; i < 3; i++ {
		fmt.Println(msg, ":", i)
	}
}

func functino01() {
	go f("goroutine")

	go func(msg string) {
		fmt.Println(msg)
	}("going")

	time.Sleep(time.Second)
	fmt.Println("done")
}

func function02() {
	ch := make(chan int, 0)
	go func() {
		time.Sleep(time.Second)
		ch <- 1
	}()
	v := <-ch
	fmt.Println(v)
}

func function03() {
	ch := make(chan int)
	go func() {
		v := <-ch
		fmt.Println(v)
	}()
	time.Sleep(time.Second)
	ch <- 1
	time.Sleep(time.Second)
}

func function04() {
	ch := make(chan int, 2)
	fmt.Println(len(ch), cap(ch)) // 0 2
	ch <- 1
	ch <- 2
	go func() {
		for v := range ch {
			fmt.Println(v)
		}
	}()
	ch <- 3
	time.Sleep(time.Second)
}

func function05() {
	for i := 0; i < 5; i++ {
		go func() {
			fmt.Println(i)
		}()
	}
	time.Sleep(time.Second)
}

func function06() {
	ch := make(chan int, 1)
	ch <- 1
	close(ch)
	go func() {
		for {
			if v, ok := <-ch; ok {
				fmt.Println(v)
			} else {
				break
			}
		}
	}()
	time.Sleep(time.Second)
}

// Producer 生产者
func Producer() <-chan int {
	ch := make(chan int, 1)
	go func() {
		for i := 0; i < 3; i++ {
			ch <- i
		}
		close(ch) // 任务完成关闭通道
	}()
	return ch
}

// Consumer 消费者
func Consumer(ch <-chan int) int {
	sum := 0
	for v := range ch {
		sum += v
	}
	return sum
}

func function07() {
	ch := Producer()
	sum := Consumer(ch)
	fmt.Println(sum) // 3
}

func function08() {
	ch := make(chan int, 1)

	go func(ch chan<- int) {
		for i := 0; i < 2; i++ {
			ch <- i
		}
		close(ch)
	}(ch)

	for v := range ch {
		fmt.Println(v)
	} // 0 1
}

// select
func function09() {
	now := time.Now()
	ch1 := make(chan string)
	ch2 := make(chan string)

	go func() {
		time.Sleep(1 * time.Second)
		ch1 <- "one"
	}()
	go func() {
		time.Sleep(2 * time.Second)
		ch2 <- "two"
	}()

	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-ch1:
			fmt.Println(msg1)
		case msg2 := <-ch2:
			fmt.Println(msg2)
		}
	} // one two
	fmt.Println(time.Since(now)) // 2.0003655s
}

var (
	x   int64
	wg  sync.WaitGroup
	mtx sync.Mutex
)

func function10() {
	add := func() {
		defer wg.Done()

		for i := 0; i < 5000; i++ {
			x = x + 1
		}
	}
	wg.Add(2)
	go add()
	go add()
	wg.Wait()
	fmt.Println(x)
}

func function11() {
	add := func() {
		defer wg.Done()

		for i := 0; i < 5000; i++ {
			mtx.Lock()
			x = x + 1
			mtx.Unlock()
		}
	}
	wg.Add(2)
	go add()
	go add()
	wg.Wait()
	fmt.Println(x) // 10000
}

type Singleton struct{}

var (
	instance *Singleton
	once     sync.Once
)

func GetInstance() *Singleton {
	once.Do(func() {
		instance = &Singleton{}
		fmt.Println("Get Instance")
	})
	return instance
}

// once.Do
func function12() {
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			_ = GetInstance()
		}()
	} // Get Instance
	wg.Wait()
}

var (
	mp = make(map[string]interface{})
)

func function13() {
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			key := strconv.Itoa(i)
			mp[key] = i
			fmt.Println(key, mp[key])
		}()
	}
	wg.Wait()
}

// sync.Map
func function14() {
	m := sync.Map{}
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			key := strconv.Itoa(i)
			m.Store(key, i)

			v, ok := m.Load(key)
			if ok {
				fmt.Println(key, v)
			}
		}()
	}
	wg.Wait()
}

// LoadOrStore、LoadAndDelete
func function15() {
	m := sync.Map{}
	//m.Store("cauchy", 19)
	v, ok := m.LoadOrStore("cauchy", 20)
	fmt.Println(v, ok) // 注释: 20 false；没注释: 19 true
	v, ok = m.Load("cauchy")
	fmt.Println(v, ok) // 注释: 20 true；没注释: 19 true

	v, ok = m.LoadAndDelete("cauchy")
	fmt.Println(v, ok) // 注释: 20 true；没注释: 19 true
	v, ok = m.Load("cauchy")
	fmt.Println(v, ok) // nil false
}

// Map.Range
func function16() {
	m := sync.Map{}
	m.Store(3, 3)
	m.Store(2, 2)
	m.Store(1, 1)
	cnt := 0
	m.Range(func(key, value any) bool {
		cnt++
		fmt.Println(key, value)
		return true
	})
	fmt.Println(cnt) // 3
}

func main() {
}
